package ua.amsoft.brelok.manager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;

import org.xmlpull.v1.XmlPullParserException;

import ua.amsoft.brelok.MainActivity;
import ua.amsoft.brelok.R;
import ua.amsoft.brelok.chart.BrelokPieChartView;
import ua.amsoft.brelok.constant.Constants;
import ua.amsoft.brelok.dto.Range;
import ua.amsoft.brelok.dto.Zone;
import ua.amsoft.brelok.service.UpdateService;
import ua.amsoft.brelok.task.FetchRangeTask;
import ua.amsoft.brelok.util.DateTimeUtils;
import ua.amsoft.brelok.widget.BrelokWidgetProvider;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;

/**
 * Manager for app widget update purposes
 * 
 * @author Tair Mustafaiev
 */
public class WidgetUpdateManager {
    
    private static final String TAG = WidgetUpdateManager.class.getName();
    
    /**
     * Updates widget views
     * 
     * @param context - {@link Context}
     * @param appWidgetManager - {@link AppWidgetManager}
     * @param appWidgetId - current widget ID
     */
    public static void updateAppWidget(final Context context,
            final AppWidgetManager appWidgetManager, final int appWidgetId) {
        Log.i(WidgetUpdateManager.TAG, "Widget updating started, ID = " + appWidgetId);
        try {
            final RemoteViews views = buildViews(context, appWidgetId);
            appWidgetManager.updateAppWidget(appWidgetId, views);
        } catch (final IOException e) {
            Log.e(WidgetUpdateManager.TAG, "Widget update failed: " + e.getLocalizedMessage());
        }
    }
    
    /**
     * Fetches the {@link Range} object
     * 
     * @param context - {@link Context}
     * @param url - server's url
     * @param imei - phone's IMEI number
     * @return parsed {@link Range} object from xml or null
     */
    private static Range getChart(final Context context, final String url, final String imei) {
        final List<Zone> zones = new ArrayList<Zone>();
        
        final Range range = new Range();
        range.setHeight(170);
        range.setWidth(170);
        
        final Zone greenZone = new Zone();
        greenZone.setColor("green");
        greenZone.setSize(73);
        zones.add(greenZone);
        
        final Zone yellowZone = new Zone();
        yellowZone.setColor("yellow");
        yellowZone.setSize(20);
        zones.add(yellowZone);
        
        final Zone redZone = new Zone();
        redZone.setColor("red");
        redZone.setSize(7);
        zones.add(redZone);
        
        range.setZones(zones);
        
        return range;
    }
    
    /**
     * Parses the {@link Range} object
     * 
     * @param context - Context
     * @param url - Server's URL
     * @param imei phone's IMEI
     * @return parsed {@link Range} object from xml
     * @throws XmlPullParserException - XML parser exception
     * @throws IOException - IO exception
     */
    public static Range parseChart(final Context context, final String url, final String imei)
            throws XmlPullParserException, IOException {
        Range chart = null;
        final FetchRangeTask chartXmlTask = new FetchRangeTask();
        try {
            chart = chartXmlTask.execute(url, imei).get();
        } catch (final InterruptedException e) {
            Log.i(WidgetUpdateManager.TAG, e.getLocalizedMessage());
        } catch (final ExecutionException e) {
            Log.i(WidgetUpdateManager.TAG, e.getLocalizedMessage());
        }
        return chart;
        
    }
    
    /**
     * Builds new app widget's view
     * 
     * @param context - {@link Context}
     * @param widgetId widget's ID
     * @return built {@link RemoteViews} object
     * @throws IOException - exception to be throwed
     */
    private static RemoteViews buildViews(final Context context, final int widgetId)
            throws IOException {
        
        final PreferencesManager configurationManager = new PreferencesManager();
        final String date = DateTimeUtils.formatInputDate(new Date());
        final String url = configurationManager
                .getPrefByName(context, Constants.PREF_URL_KEY, null);
        final String imei = configurationManager.getPrefByName(context, Constants.PREF_IMEI_KEY,
                null);
        final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
        addOnChartClickHandler(context, widgetId, views);
        
        resolveUpdateActions(context, date, url, imei, views);
        views.setTextViewText(R.id.last_updated, date);
        views.setViewVisibility(R.id.refresh, View.VISIBLE);
        views.setViewVisibility(R.id.widget_refresh_progress, View.INVISIBLE);
        
        return views;
    }
    
    /**
     * Resolves what update remote views process should do according to network
     * and server state
     * 
     * @param context - Context
     * @param date -
     * @param url - Server's URL
     * @param imei phone's IMEI
     * @param views {@link RemoteViews}
     * @throws IOException exception to be thrown
     */
    private static void resolveUpdateActions(final Context context, final String date,
            final String url, final String imei, final RemoteViews views) throws IOException {
        final ConnectionManager connectionManager = new ConnectionManager();
        final boolean isNetworkConnected = connectionManager.isNetworkConnected(context);
        if (isNetworkConnected && connectionManager.isServerReachable(url)) {
            final PendingIntent pendingIntent = createIntent(context);
            final Range chart = getChart(context, url, imei);
            if (chart != null) {
                buildChartView(context, views, chart);
            }
            views.setOnClickPendingIntent(R.id.refresh, pendingIntent);
            views.setTextViewText(R.id.last_updated, date);
            views.setTextViewText(R.id.status, context.getString(R.string.text_status_online));
        } else if (!isNetworkConnected) {
            views.setTextViewText(R.id.status,
                    context.getString(R.string.error_network_disconnected));
        } else {
            views.setTextViewText(R.id.status, context.getString(R.string.error_server_unavailable));
        }
    }
    
    /**
     * Adds an click handler for chart
     * 
     * @param context - {@link Context}
     * @param widgetId - widget's ID
     * @param views {@link RemoteViews}
     */
    private static void addOnChartClickHandler(final Context context, final int widgetId,
            final RemoteViews views) {
        final Intent intent = new Intent(context, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(BrelokWidgetProvider.OPEN_MAIN_ACTIVITY);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
        final PendingIntent chartClickPendingIntent = PendingIntent.getActivity(context,
                (int) (Math.random() * 10000), intent, 0);
        views.setOnClickPendingIntent(R.id.pie_chart, chartClickPendingIntent);
    }
    
    /**
     * Builds the chart view
     * 
     * @param context - {@link Context}
     * @param views - {@link RemoteViews}
     * @param chart - chart
     */
    private static void buildChartView(final Context context, final RemoteViews views,
            final Range chart) {
        final int chartHeight = 150;
        final int chartWidth = 150;
        chart.setHeight(chartHeight);
        chart.setWidth(chartWidth);
        final BrelokPieChartView chartView = new BrelokPieChartView(context, chart);
        chartView.layout(0, 0, chartHeight, chartWidth);
        chartView.setDrawingCacheEnabled(true);
        final Bitmap bitmap = chartView.getDrawingCache();
        views.setImageViewBitmap(R.id.pie_chart, bitmap);
    }
    
    /**
     * Creates an {@link Intent} for UpdateService start
     * 
     * @param context - Context
     * @return {@link PendingIntent}
     */
    private static PendingIntent createIntent(final Context context) {
        final Intent intent = new Intent(context, UpdateService.class);
        final PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
        return pendingIntent;
    }
    
}
